//-------------------Sonic CD Sonic Script--------------------//
//--------Scripted by Christian Whitehead 'The Taxman'--------//
//-------Unpacked By Rubberduckycooly's Script Unpacker-------//

// Aliases

// These are three sets of aliases, this object is rather inconsistent in its variable use, where sometimes
// normal Object.Values are used, but then other times, Player. values are used instead
// For the sake of simplicity, these have all been merged into a SSSonic. namespace via aliases

// Value aliases
private alias Object.Value0 : SSSonic.ZPos
private alias Object.Value1 : SSSonic.FrameLoop
private alias Object.Value2 : SSSonic.FrameEnd
private alias Object.Value3 : SSSonic.FrameTimer
private alias Object.Value4 : SSSonic.Unused // Completely unused
private alias Object.Value5 : SSSonic.ScreenDepth // Same use as other Special Stage objects, see Special Setup
private alias Object.Value6 : SSSonic.Timer
private alias Object.Value7 : SSSonic.Tilt
private alias object.value10 : SSSonic.ScreenXPos
private alias object.value11 : SSSonic.ScreenYPos

private alias object.value13 : SSonic.invulnerable

private alias object[2].controlMode : SSSonic.ControlMode
private alias object[2].speed : SSSonic.Speed
private alias object[2].angle : SSSonic.Angle
private alias object[2].xpos : SSSonic.XPos
private alias object[2].ypos : SSSonic.YPos
private alias Player.ScreenXPos : SSSonic.ScreenXPos
private alias Player.ScreenYPos : SSSonic.ScreenYPos
private alias object.yvel : SSSonic.YVelocity

// Object. aliases
private alias Object.Type : SSSonic.Type
private alias Object.Priority : SSSonic.Priority
private alias Object.State : SSSonic.State
private alias Object.Frame : SSSonic.Frame
private alias Object.Direction : SSSonic.Direction
private alias Object.AnimationSpeed : SSSonic.AnimationSpeed

// State aliases
private alias 0  : SSSONIC_INTROPOSE
private alias 1  : SSSONIC_INTROTURNAROUND
private alias 2  : SSSONIC_WALKING
private alias 3  : SSSONIC_JUMPING
private alias 4  : SSSONIC_SPEEDBOOSTER
private alias 5  : SSSONIC_FAN
private alias 6  : SSSONIC_TRIPPED
private alias 7  : SSSONIC_SPEEDSHOESRUN
private alias 8  : SSSONIC_FINISHSTAND
private alias 9  : SSSONIC_CAMERAPAN
private alias 10 : SSSONIC_STONEGRABBED
private alias 11 : SSSONIC_SPRING
private alias 12 : SSONIC_IDLE
private alias 13 : SSONIC_DEAD
private alias 14 : SSSONIC_HURT

// Animation aliases
// Most are divided into three parts where there's the animation's start, its loop point, and its end
// This is to match with how this Object animates itself, check out Sonic_ProcessAnimation for more info

private alias 1 : ANI_STANDING_START
// This standing animation doesn't, well, animate, so no extended aliases needed here

private alias 2 : ANI_FACINGAHEAD_START
private alias 4 : ANI_FACINGAHEAD_LOOP
private alias 4 : ANI_FACINGAHEAD_END

private alias 5 : ANI_INTROPOSE_START
private alias 5 : ANI_INTROPOSE_LOOP
private alias 8 : ANI_INTROPOSE_END

private alias 9  : ANI_WALKING_START
private alias 9  : ANI_WALKING_LOOP
private alias 14 : ANI_WALKING_END

private alias 39 : ANI_JUMPING_START
private alias 39 : ANI_JUMPING_LOOP
private alias 42 : ANI_JUMPING_END

private alias 43 : ANI_BRAKING_START
private alias 43 : ANI_BRAKING_LOOP
private alias 47 : ANI_BRAKING_END

private alias 48 : ANI_FAN_START
private alias 48 : ANI_FAN_LOOP
private alias 53 : ANI_FAN_END

private alias 54 : ANI_TRIP_START
private alias 54 : ANI_TRIP_LOOP
private alias 76 : ANI_TRIP_END

private alias 77 : ANI_RUN_START
private alias 77 : ANI_RUN_LOOP
private alias 80 : ANI_RUN_END

// HUD Aliases
private alias Object.Value0 : HUD.UFOsCount
private alias Object.Value3 : HUD.Rings
private alias Object.Value4 : HUD.LastUFOType
private alias Object.Value5 : HUD.SpeedShoes

// Ring Aliases
private alias Object.Value0 : Ring.ZPos
private alias Object.Value1 : Ring.XVelocity
private alias Object.Value2 : Ring.YVelocity
private alias Object.Value3 : Ring.ZVelocity

// Touch Control Aliases
// This value is used to store if the jump button was touched last frame, to help differenciate new taps from old holds
private alias Object.Value7 : TouchControls.TouchJump

// Generic Object Alias
// (Here it's only used for the Water Splash object, but it does apply to every SS game object as well)
private alias Object.Value5 : Object.ScreenDepth

// Player aliases
private alias 0 : PLAYER_SONIC_A
private alias 1 : PLAYER_TAILS_A

// Global SFX
private alias 0  : SFX_G_JUMP
private alias 4  : SFX_G_LOSERINGS
private alias 11 : SFX_G_SPRING
private alias 24 : SFX_G_FLYING
private alias 25 : SFX_G_TIRED
private alias 27 : SFX_G_SELECT

// Stage SFX
private alias 2 : SFX_S_BUMPER2
private alias 3 : SFX_S_LARGEBOOSTER
private alias 4 : SFX_S_SMALLBOOSTER
private alias 6 : SFX_S_FAN

// ControlMode Aliases
private alias -1 : CONTROLMODE_NONE
private alias  0 : CONTROLMODE_NORMAL

// Engine Callback Aliases
private alias 13 : CALLBACK_PAUSE_REQUESTED

// Engine Messages
private alias 2 : MESSAGE_LOSTFOCUS

// Priority
private alias 1 : PRIORITY_ACTIVE
private alias 2 : PRIORITY_ALWAYS

// Tile Layer types
private alias 3 : LAYER_3DFLOOR

// Tile Info
private alias 1 : TILEINFO_DIRECTION
private alias 6 : TILEINFO_ANGLEA

// Stage Finish Aliases
private alias Object.PropertyValue : Object.ResultsType

private alias 1 : STAGEFINISH_T_STONEOBTAINED



public value PlayerHealth = 3;


function Sonic_ProcessPlayer
	
	if Options.AttractMode == false

		// Standard doesn't need nearly as much code as mobile to handle its inputs,
		// thanks to the lack of a touchscreen and other mobile things
		if SSSonic.ControlMode == CONTROLMODE_NORMAL
			
			CheckTouchRect(0, 96, screen.xcenter, screen.ysize)
			if checkResult > -1
				arrayPos0 = checkResult
				temp0 = touchscreen[arrayPos0].xpos
				temp0 -= 56
				temp1 = touchscreen[arrayPos0].ypos
				temp1 -= 184
				ATan2(temp2, temp0, temp1)
				temp2 += 16
				temp2 &= 255
				temp2 >>= 5
				switch temp2
				case 0
					inputDown.right = true
					break
				case 1
					inputDown.right = true
					inputDown.down = true
					break
				case 2
					inputDown.down = true
					break
				case 3
					inputDown.down = true
					inputDown.left = true
					break
				case 4
					inputDown.left = true
					break
				case 5
					inputDown.left = true
					inputDown.up = true
					break
				case 6
					inputDown.up = true
					break
				case 7
					inputDown.up = true
					inputDown.right = true
					break
				end switch
			end if
			CheckTouchRect(screen.xcenter, 96, screen.xsize, 240)
			if checkResult > -1
				inputDown.buttonA = 1
			end if
			if touchJump == 0
				inputPress.buttonA |= inputDown.buttonA
			end if
			touchJump = inputDown.buttonA
			if stage.debugMode == 1
				CheckTouchRect(0, 0, 122, 56)
				if checkResult > -1
					inputDown.buttonB = 1
				end if
				if touchDebug == 0
					inputPress.buttonB |= inputDown.buttonB
				end if
				touchDebug = inputDown.buttonB
			end if
			temp0=screen.xsize
			temp0-=90
			CheckTouchRect(temp0, 0, screen.xsize, 40)
			if checkResult > -1
				inputpress[1].Start = true
			end if
			temp0 -= 37
			temp1 = screen.xsize
			temp1 -= 95
			CheckTouchRect(temp0, 0, temp1, 40)				
			if checkResult > -1
				inputDown.buttonY = 1
			end if
			if touchMisc == 0
				inputPress.buttonY |= inputDown.buttonY
			end if
			touchMisc = inputDown.buttonY
		

			// Make sure no Pause Menu object exists already
			if Object[9].Type == TypeName[Blank Object]
				if inputpress[1].Start == true
					
					// Clear the Start state in order to avoid "double-pauses" oddities
					inputpress[1].Start = false
					
					inputpress[0].Start = false
					stage.state =  STAGE_FROZEN
					PauseMusic()
					ResetObjectEntity(9, TypeName[Pause Menu], 0, 0, 0)
					object[9].propertyValue = 10
					object[9].DrawOrder = 6
					object[9].Priority = PRIORITY_ACTIVE
						// The floor should already be 3d, this is actually a form of exiting High Quality mode
						TileLayer[0].Type = LAYER_3DFLOOR					
				end if
			end if
		

		end if

		
		// Assign all Player.* input values to their corresponding Input.* values
		ProcessObjectControl()
		
	end if // Options.AttractMode == false
	
end function


function Sonic_HandlePause
	
	// This function is only called while tripped, it's nearly identical to the normal pause function with the exception of control values not being set
	// Don't really know why this exists, but there's probably some reason
	
	if Options.AttractMode == false
		if SSSonic.ControlMode == CONTROLMODE_NORMAL
			
			// Make sure the Pause Menu doesn't already exist
			if Object[9].Type == TypeName[Blank Object]
				
				// See if the player's touched the pause button
				CheckTouchRect(240, 0, Screen.XSize, 40)
				if CheckResult > -1
					
					// Pause the entire stage, including its objects
					Stage.State = STAGE_PAUSED
					
					// And pause the music too
					// Not completely stopping the music though, since it'll possibly resumed later
					PauseMusic()
					
					// SFX
					PlaySfx(SFX_G_SELECT, false)
					StopSfx(SFX_G_FLYING)
					StopSfx(SFX_G_TIRED)
					
					// Create the pause menu and initialise its values
					// - Object Type of [Pause Menu] (of course)
					// - High Draw Order, above other things like even the HUD
					// - Priority of PRIORITY_ALWAYS, since the Object should continue running even while the stage is paused
					Object[9].Type = TypeName[Pause Menu]
					Object[9].DrawOrder = 6
					Object[9].Priority = PRIORITY_ALWAYS
					
					// Disable frameskip when paused

					
					// Make the floor lower quality instead while paused, to be more efficient
					TileLayer[0].Type = LAYER_3DFLOOR
					
				end if
				
				// Check if focus was lost (as in, the player exiting the game)

			end if
		end if

		

		if SSSonic.ControlMode == CONTROLMODE_NORMAL
			
			// Make sure the game isn't already paused via checking if the Pause Menu object exists or not
			if Object[9].Type == TypeName[Blank Object]
				if inputpress[1].Start == true
					
					// Disable start for this frame, this'll help with "double-pausing" cases
					inputpress[1].Start = false
					
					// Give different pause menus depending on if the player was brought here from the Dev Menu
					// (...but why?)
				
						
						// Pause the stage, this'll pause all the stage's objects too
						Stage.State = STAGE_PAUSED
						
						// and pause the stage's music, as well
						PauseMusic()
						
						// SFX dealings
						PlaySfx(SFX_G_SELECT, false)
						StopSfx(SFX_G_FLYING)
						StopSfx(SFX_G_TIRED)
						
						// Create the Pause Menu and set it up as needed
						Object[9].Type = TypeName[Pause Menu]
						Object[9].DrawOrder = 6
						Object[9].Priority = PRIORITY_ALWAYS
						
						// Turn the floor into low-quality 3d
						TileLayer[0].Type = LAYER_3DFLOOR
						
					
				end if
			end if
		end if

	end if // Options.AttractMode == false
	
end function


function Sonic_HandleMovement
	
	// Update Sonic's tilt based on what directions the player is currently holding
	// Left takes priority over right, similarly to the maingame
	if object.Left == true
		SSSonic.Tilt--
		
		// Min tilt of -8
		if SSSonic.Tilt < -8
			SSSonic.Tilt = -8
		end if
	else
		if object.Right == true
			SSSonic.Tilt++
			
			// Max tilt of 8
			if SSSonic.Tilt > 8
				SSSonic.Tilt = 8
			end if
		else
			// Neither left nor right are held, restore Sonic's tilt to neutral position
			
			if SSSonic.Tilt > 0
				SSSonic.Tilt--
			end if
			
			if SSSonic.Tilt < 0
				SSSonic.Tilt++
			end if
		end if
	end if
	
	if object.Left == true
		SSSonic.Angle += 8
	end if
	
	if object.Right == true
		SSSonic.Angle -= 8
	end if
	
	if SSSonic.Angle < 0
		// It's worth noting, Angle uses a 512-based value, which is why this is "allowed"
		SSSonic.Angle += 512
	end if
	
	SSSonic.Angle &= 511
	
	// Update movement based on the object's angle
	
	Sin(temp0, SSSonic.Angle)
	temp0 *= SSSonic.Speed
	temp0 >>= 9
	SSSonic.XPos += temp0
	
	Cos(temp0, SSSonic.Angle)
	temp0 *= SSSonic.Speed
	temp0 >>= 9
	SSSonic.ZPos += temp0
	
end function


function Sonic_ProcessAnimation
	
	// This function is used for animating the object, here's a short overview of the values it uses
	// (Frame values are in accordance with SpriteFrames set in ObjectStartup)
	// -> SSSonic.AnimationSpeed is the speed at which Sonic should animate, it's added to his timer every frame
	// -> SSSonic.FrameTimer is the timer used for animating Sonic, think of it akin to Object.AnimationTimer
	//     - The next frame is triggered whenever the value is 240 or above, the speed is controlled by SSSonic.AnimationSpeed
	//     - This doesn't get reset whenever the frame transitions, so keep that in mind too
	// -> SSSonic.FrameEnd is the final frame of the animation
	// -> SSSonic.FrameLoop is the loop point for the animation to go back to after reaching its end
	// -> SSSonic.Frame is the frame to be displayed when drawing the object
	
	// For each animation's corresponding values, check out the ANI_* aliases up above
	
	SSSonic.FrameTimer += SSSonic.AnimationSpeed
	
	if SSSonic.FrameTimer > 239
		SSSonic.FrameTimer -= 240
		
		SSSonic.Frame++
		if SSSonic.Frame > SSSonic.FrameEnd
			SSSonic.Frame = SSSonic.FrameLoop
		end if
	end if
	
end function


function Sonic_HandleBumperInteraction
	
	// Preconditions:
	// - temp0 is object's truncated XPos, and
	// - temp1 is truncated ZPos
	
	// Reset temp2, it's gonna get used as a bitfield for where bumper collision has been sensed,
	// see below for which bits correspond to what "sensors"
	temp2 = 0
	
	// Check upper-left tile, uses the first bit
	temp0 -= 8
	temp1 -= 8
	Get16x16TileInfo(CheckResult, temp0, temp1, TILEINFO_ANGLEA)
	if CheckResult == 3
		SetBit(temp2, 0, true)
	end if
	
	// Check upper-right tile, uses the second bit
	temp0 += 16
	Get16x16TileInfo(CheckResult, temp0, temp1, TILEINFO_ANGLEA)
	if CheckResult == 3
		SetBit(temp2, 1, true)
	end if
	
	// Check bottom left tile, uses the third bit
	temp0 -= 16
	temp1 += 16
	Get16x16TileInfo(CheckResult, temp0, temp1, TILEINFO_ANGLEA)
	if CheckResult == 3
		SetBit(temp2, 2, true)
	end if
	
	// Check bottom right tile, uses the fourth bit
	temp0 += 16
	Get16x16TileInfo(CheckResult, temp0, temp1, TILEINFO_ANGLEA)
	if CheckResult == 3
		SetBit(temp2, 3, true)
	end if
	
	// Was any collision sensed?
	if temp2 > 0
		temp3 = SSSonic.Speed
		temp3 += 0x10000
		

		
		SSSonic.Timer = 32
		
		// Jump to the corresponding collision match, each match is labelled in accordance with what sensors are triggered
		
		switch temp2
		case 1 // Upper left tile only
			SSSonic.ScreenXPos = temp3
			SSSonic.ScreenYPos = temp3
			break
		
		case 2 // Upper right tile only
			SSSonic.ScreenXPos = temp3
			SSSonic.ScreenYPos = temp3
			FlipSign(SSSonic.ScreenXPos)
			break
		
		case 3 // Upper left tile and upper right
			SSSonic.ScreenXPos = 0
			SSSonic.ScreenYPos = temp3
			break
		
		case 4 // Bottom left tile only
			SSSonic.ScreenXPos = temp3
			SSSonic.ScreenYPos = temp3
			FlipSign(SSSonic.ScreenYPos)
			break
		
		case 5 // Upper left tile and bottom left tile
			SSSonic.ScreenXPos = temp3
			SSSonic.ScreenYPos = 0
			break
		
		case 6 // Upper right tile and bottom left tile
		case 7 // Upper left tile, upper right tile, and bottom left tile
			SSSonic.ScreenXPos = temp3
			SSSonic.ScreenYPos = temp3
			break
		
		case 8  // Bottom right tile only
		case 14 // Upper right tile, bottom left tile, and bottom right tile
		case 15 // Upper left tile, upper right tile, bottom left tile, and bottom right tile
			SSSonic.ScreenXPos = temp3
			SSSonic.ScreenYPos = temp3
			FlipSign(SSSonic.ScreenXPos)
			FlipSign(SSSonic.ScreenYPos)
			break
		
		case 9  // Upper left tile and bottom right tile
		case 11 // Upper left tile, upper right tile, and bottom right tile
			SSSonic.ScreenXPos = temp3
			SSSonic.ScreenYPos = temp3
			FlipSign(SSSonic.ScreenXPos)
			break
		
		case 10 // Upper right tile and bottom right tile
			SSSonic.ScreenXPos = temp3
			SSSonic.ScreenYPos = 0
			FlipSign(SSSonic.ScreenXPos)
			break
		
		case 12 // Bottom left tile and bottom right tile
			SSSonic.ScreenXPos = 0
			SSSonic.ScreenYPos = temp3
			FlipSign(SSSonic.ScreenYPos)
			break
		
		case 13 // Upper left tile, bottom left tile, and bottom right tile
			SSSonic.ScreenXPos = temp3
			SSSonic.ScreenYPos = temp3
			FlipSign(SSSonic.ScreenYPos)
			break
		
		end switch
	end if
	
end function


function Sonic_HandleTileInteractions
	
	// Get the player's truncated XPos and ZPos for tile collision purposes
	temp0 = SSSonic.XPos
	temp0 >>= 16
	temp1 = SSSonic.ZPos
	temp1 >>= 16
	
	// Pass the results over to the bumper function for bumping interations
	CallFunction(Sonic_HandleBumperInteraction)
	
	// Get the player's truncated XPos and ZPos for tile collision purposes (again)
	temp0 = SSSonic.XPos
	temp0 >>= 16
	temp1 = SSSonic.ZPos
	temp1 >>= 16
	
	// Find what tile type the player is currently standing on
	Get16x16TileInfo(CheckResult, temp0, temp1, TILEINFO_ANGLEA)
	switch CheckResult
	case 1
		// Offroad tile, slow down Sonic and kick up some dust
		Object[3].Type = TypeName[Dust Puff]
		
		// Note that we're giving it a Draw Order of 4, not only does this make it draw above Sonic but
		//  more importantly this makes it so that it won't be treated as a 3d object
		Object[3].DrawOrder = 4
		
		if HUD[4].SpeedShoes == 0
			if SSSonic.Speed > 0x28000
				// While on dust without speed shoes, the maximum speed is 2.5 px per frame
				SSSonic.Speed = 0x28000
			end if
		else
			if SSSonic.Speed > 0x50000
				// While on dust *with* speed shoes, the maximum speed is now bumped up to 5 px per frame
				SSSonic.Speed = 0x50000
			end if
		end if
		break
		
	case 2
		// Water tile, slow down the player and make a splash
		Object[3].Type = TypeName[WaterSplash]
		Object[3].DrawOrder = 4
		
		// Give the water splash a Z Pos of just a tad bit lower than Sonic, in order to make it draw behind him
		Object[3].ScreenDepth = 0x57FE
		
		if HUD[4].SpeedShoes > 0
			if SSSonic.Speed > 0x50000
				// If Sonic has speed shoes, then enforce a max speed of 5px per frame
				SSSonic.Speed = 0x50000
			end if
		end if
		break
		
	// 3, the value used by the bumper tiles, is skipped here
	// It's handled in Sonic_HandleBumperInteraction instead, called above
	
	case 4
		// Ouch, a Cruncher!
		// Make Sonic fall
		
		SSSonic.State     = SSSONIC_TRIPPED
		SSSonic.Timer     = 136
		
		SSSonic.Frame     = ANI_TRIP_START
		SSSonic.FrameLoop = ANI_TRIP_LOOP
		SSSonic.FrameEnd  = ANI_TRIP_END
		
		SSSonic.AnimationSpeed = 40
		SSSonic.FrameTimer = 0
		
		// Go to a speed of 1px per frame
		SSSonic.Speed = 0x10000
		
		if HUD[4].Rings > 0
			PlaySfx(SFX_G_LOSERINGS, false)
			
			// Cut the player's rings in half
			temp0 = HUD[4].Rings
			HUD[4].Rings >>= 1
			
			// Find how many rings were lost
			temp0 -= HUD[4].Rings
			
			// Max of 8 rings can be dropped
			if temp0 > 8
				temp0 = 8
			end if
			
			// If Sonic has 0 rings now, then reset the UFO streak
			if HUD[4].Rings == 0
				HUD[4].LastUFOType = -1
			endif
			
			// Create all the dropped rings
			while temp0 > 0
				CreateTempObject(TypeName[Ring], 0, SSSonic.XPos, 0)
				Object[TempObjectPos].Priority = PRIORITY_ACTIVE
				
				// Move the Ring to Sonic
				// (XPos is matched already via object spawning function)
				Ring[TempObjectPos].ZPos = SSSonic.ZPos
				
				// Randomise the X Velocity
				Rand(temp1, 64)
				temp1 -= 32
				temp1 <<= 10
				Ring[TempObjectPos].XVelocity = temp1
				
				// Make the Rings fall in the general direction of Sonic, though
				Sin(temp1, SSSonic.Angle)
				temp1 *= 96
				Ring[TempObjectPos].XVelocity += temp1
				
				// Randomise the Y Velocity as well
				Rand(temp1, 64)
				temp1 += 32
				temp1 <<= 12
				Ring[TempObjectPos].YVelocity = temp1
				
				// No further stuff needed for Y Velocity since there's really only one way for them to go - up!
				
				// Randomise the Ring's Z Velocity too
				Rand(temp1, 64)
				temp1 -= 32
				temp1 <<= 10
				Ring[TempObjectPos].ZVelocity = temp1
				
				// And make it somewhat match Sonic's direction
				Cos(temp1, SSSonic.Angle)
				temp1 *= 96
				Ring[TempObjectPos].ZVelocity += temp1
				
				temp0--
			loop
		end if
		break
	
	case 5
		// Spring, send the player up, up, and away into the skies
		SSSonic.State     = SSSONIC_SPRING
		SSSonic.Timer     = 0
		
		SSSonic.Frame     = ANI_JUMPING_START
		SSSonic.FrameLoop = ANI_JUMPING_LOOP
		SSSonic.FrameEnd  = ANI_JUMPING_END
		
		SSSonic.AnimationSpeed = 80
		SSSonic.FrameTimer = 0
		
		// Ascending at a rate of 8.75 pixels per frame
		SSSonic.YVelocity = 0x8C000
		
		PlaySfx(SFX_G_SPRING, false)
		break
		
	case 6
		// Fan, starting gliding
		SSSonic.State     = SSSONIC_FAN
		SSSonic.Timer     = 0
		
		SSSonic.Frame     = ANI_FAN_START
		SSSonic.FrameLoop = ANI_FAN_LOOP
		SSSonic.FrameEnd  = ANI_FAN_END
		
		SSSonic.AnimationSpeed = 24
		SSSonic.FrameTimer = 0
		
		// Fans don't give that much upwards boost, only giving a starting velocity of 2.5 pixels per frame
		SSSonic.YVelocity = 0x28000
		
		
		break
		
	case 7
		// Large arrow booster pad, facing left
		SSSonic.Timer = 40
		SSSonic.ScreenXPos = -0xC0000
		SSSonic.ScreenYPos = 0
		
		// Get the tile's flip directions
		Get16x16TileInfo(CheckResult, temp0, temp1, TILEINFO_DIRECTION)
		
		// Flip Sonic's direction if needed
		if CheckResult == 1
			FlipSign(SSSonic.ScreenXPos)
		else
			if CheckResult == 3
				FlipSign(SSSonic.ScreenXPos)
			end if
		end if
		
	
		
		SSSonic.State     = SSSONIC_SPEEDBOOSTER
		
		SSSonic.Frame     = ANI_BRAKING_START
		SSSonic.FrameLoop = ANI_BRAKING_LOOP
		SSSonic.FrameEnd  = ANI_BRAKING_END
		
		SSSonic.AnimationSpeed = 24
		SSSonic.FrameTimer = 0
		break
		
	case 8
		// Large arrow booster pad, facing right
		SSSonic.Timer = 40
		SSSonic.ScreenXPos = 0xC0000
		SSSonic.ScreenYPos = 0
		
		// Get the tile's flip directions
		Get16x16TileInfo(CheckResult, temp0, temp1, TILEINFO_DIRECTION)
		
		// Flip Sonic's direction if needed
		if CheckResult == 1
			FlipSign(SSSonic.ScreenXPos)
		else
			if CheckResult == 3
				FlipSign(SSSonic.ScreenXPos)
			end if
		end if
		

		
		SSSonic.State     = SSSONIC_SPEEDBOOSTER
		
		SSSonic.Frame     = ANI_BRAKING_START
		SSSonic.FrameLoop = ANI_BRAKING_LOOP
		SSSonic.FrameEnd  = ANI_BRAKING_END
		
		SSSonic.AnimationSpeed = 24
		SSSonic.FrameTimer = 0
		break
		
	case 9
		// Large arrow booster pad, facing up
		SSSonic.Timer = 40
		SSSonic.ScreenXPos = 0
		SSSonic.ScreenYPos = -0xC0000
		
		// Get the tile's flip directions
		Get16x16TileInfo(CheckResult, temp0, temp1, TILEINFO_DIRECTION)
		
		// Flip Sonic's direction if needed
		if CheckResult == 2
			FlipSign(SSSonic.ScreenYPos)
		else
			if CheckResult == 3
				FlipSign(SSSonic.ScreenYPos)
			end if
		end if
		
		
		
		SSSonic.State     = SSSONIC_SPEEDBOOSTER
		
		SSSonic.Frame     = ANI_BRAKING_START
		SSSonic.FrameLoop = ANI_BRAKING_LOOP
		SSSonic.FrameEnd  = ANI_BRAKING_END
		
		SSSonic.AnimationSpeed = 24
		SSSonic.FrameTimer = 0
		break
		
	case 10
		// Large arrow booster pad, facing down
		SSSonic.Timer = 40
		SSSonic.ScreenXPos = 0
		SSSonic.ScreenYPos = 0xC0000
		
		// Get the tile's flip directions
		Get16x16TileInfo(CheckResult, temp0, temp1, TILEINFO_DIRECTION)
		
		// Flip Sonic's direction if needed
		if CheckResult == 2
			FlipSign(SSSonic.ScreenYPos)
		else
			if CheckResult == 3
				FlipSign(SSSonic.ScreenYPos)
			end if
		end if
		
	
		
		SSSonic.State     = SSSONIC_SPEEDBOOSTER
		
		SSSonic.Frame     = ANI_BRAKING_START
		SSSonic.FrameLoop = ANI_BRAKING_LOOP
		SSSonic.FrameEnd  = ANI_BRAKING_END
		
		SSSonic.AnimationSpeed = 24
		SSSonic.FrameTimer = 0
		break
		
	case 11
		// Small arrow booster pad, facing left
	
		SSSonic.Timer = 16
		SSSonic.ScreenXPos = -0x80000
		SSSonic.ScreenYPos = 0
		
		// Get the tile's flip directions
		Get16x16TileInfo(CheckResult, temp0, temp1, TILEINFO_DIRECTION)
		
		// Flip Sonic's direction if needed
		if CheckResult == 1
			FlipSign(SSSonic.ScreenXPos)
		else
			if CheckResult == 3
				FlipSign(SSSonic.ScreenXPos)
			end if
		end if
		break
		
	case 12
		// Small arrow booster pad, facing right
		
		SSSonic.Timer = 16
		SSSonic.ScreenXPos = 0x80000
		SSSonic.ScreenYPos = 0
		
		// Get the tile's flip directions
		Get16x16TileInfo(CheckResult, temp0, temp1, TILEINFO_DIRECTION)
		
		// Flip Sonic's direction if needed
		if CheckResult == 1
			FlipSign(SSSonic.ScreenXPos)
		else
			if CheckResult == 3
				FlipSign(SSSonic.ScreenXPos)
			end if
		end if
		break
		
	case 13
		// Small arrow booster pad, facing up
	
		SSSonic.Timer = 16
		SSSonic.ScreenXPos = 0
		SSSonic.ScreenYPos = -0x80000
		
		// Get the tile's flip directions
		Get16x16TileInfo(CheckResult, temp0, temp1, TILEINFO_DIRECTION)
		
		// Flip Sonic's direction if needed
		if CheckResult == 2
			FlipSign(SSSonic.ScreenYPos)
		else
			if CheckResult == 3
				FlipSign(SSSonic.ScreenYPos)
			end if
		end if
		break
		
	case 14
		// Small arrow booster pad, facing down

		
		SSSonic.Timer = 16
		SSSonic.ScreenXPos = 0
		SSSonic.ScreenYPos = 0x80000
		
		// Get the tile's flip directions
		Get16x16TileInfo(CheckResult, temp0, temp1, TILEINFO_DIRECTION)
		
		// Flip Sonic's direction if needed
		if CheckResult == 2
			FlipSign(SSSonic.ScreenYPos)
		else
			if CheckResult == 3
				FlipSign(SSSonic.ScreenYPos)
			end if
		end if
		break
	end switch
	
end function


event ObjectMain
	// Update Speed Shoes, the value's stored within the HUD object for whatever reason
	if HUD[4].SpeedShoes > 0
		HUD[4].SpeedShoes--
	end if


	if SSonic.invulnerable > 0
		SSonic.invulnerable--
		GetBit(temp0, SSonic.invulnerable, 2)
		if temp0 == 1
			object.visible = 0
		else
			object.visible = 1
		end if
	end if


	if PlayerHealth == 0
		
		SSSonic.State = SSONIC_DEAD
		SSSonic.Timer     = 0	
		SSSonic.ControlMode = 0
		SSSonic.Speed = 0
	
	end if

	
	switch SSSonic.State
	case SSSONIC_INTROPOSE
		CallFunction(Sonic_ProcessAnimation)
		SSSonic.Timer++
		if SSSonic.Timer == 120
			// Stop posing and start turning around
			SSSonic.Timer = 0
			
			SSSonic.State     = SSSONIC_INTROTURNAROUND
			
			SSSonic.Frame     = ANI_FACINGAHEAD_START
			SSSonic.FrameLoop = ANI_FACINGAHEAD_LOOP
			SSSonic.FrameEnd  = ANI_FACINGAHEAD_END
			
			SSSonic.FrameTimer = 0
			SSSonic.AnimationSpeed = 20
		end if
		break
		
	case SSSONIC_INTROTURNAROUND
		CallFunction(Sonic_ProcessAnimation)
		SSSonic.Timer++
		if SSSonic.Timer == 140
			// Fully turned around now and ready to go!
			SSSonic.Timer = 0
			
			// Start advancing ahead
			SSSonic.State     = SSONIC_IDLE
			
		//	SSSonic.Frame     = ANI_WALKING_START
		//	SSSonic.FrameLoop = ANI_WALKING_LOOP
		//	SSSonic.FrameEnd  = ANI_WALKING_END
			
			SSSonic.Speed = 0
		end if
		break
		
	case SSSONIC_WALKING
		CallFunction(Sonic_ProcessPlayer)
		if inputdown.up == 1	//if holding up, move
			if SSSonic.Speed < 0x40000
				SSSonic.Speed += 0x1000
			else
				SSSonic.Speed = 0x40000
			end if
		end if	//else slow down
		if inputdown.down == 1
			if SSSonic.Speed > -0x40000
				SSSonic.Speed -= 0x1000
			else
				SSSonic.Speed = -0x40000
			end if
		end if

		CheckEqual(inputdown.up, 0)
		temp1 = checkResult
		CheckEqual(inputdown.down, 0)
		temp1 &= checkResult		
		if temp1 == 1
			if SSSonic.Speed >= 0
				SSSonic.Speed -= 0x1000
			else	//if ur speed is 0 ur idle again
				SSSonic.Speed = 0
				SSSonic.state = SSONIC_IDLE
			end if
		end if
		
	
		

		
		// Sonic's animation speed is dependant on his actual speed
		SSSonic.AnimationSpeed = SSSonic.Speed
		SSSonic.AnimationSpeed *= 15
		SSSonic.AnimationSpeed /= 0x14000
		SSSonic.AnimationSpeed += 20
		
		CallFunction(Sonic_HandleMovement)
		CallFunction(Sonic_ProcessAnimation)
		
		// Update Sonic's gimmick interaction timer
		if SSSonic.Timer > 0
			SSSonic.Timer--
			SSSonic.XPos += SSSonic.ScreenXPos
			SSSonic.ZPos += SSSonic.ScreenYPos
		end if
		
	//	CallFunction(Sonic_HandleTileInteractions)
		
		// Check for jumping
		if object.JumpPress == true
			SSSonic.State     = SSSONIC_JUMPING
			SSSonic.Timer     = 0
			SSSonic.Frame     = ANI_JUMPING_START
			SSSonic.FrameLoop = ANI_JUMPING_LOOP
			SSSonic.FrameEnd  = ANI_JUMPING_END
			SSSonic.FrameTimer = 0
			SSSonic.AnimationSpeed = 80
			SSSonic.YVelocity = 0x46000
			PlaySfx(SFX_G_JUMP, false)
		end if
		break
		
	case SSSONIC_JUMPING
		CallFunction(Sonic_ProcessPlayer)

		if inputdown[1].Down == true
			SSSonic.Speed -= 0x0C00
			
			if SSSonic.Speed < 0x1E000
				SSSonic.Speed = 0x1E000
			end if
		end if
		
		if object.JumpHold == false
			if SSSonic.YVelocity > 0x2A000
				SSSonic.YVelocity = 0x2A000
			end if
		end if
		
		CallFunction(Sonic_HandleMovement)
		CallFunction(Sonic_ProcessAnimation)
		
		// Gravity of 0.125 per frame
		SSSonic.YVelocity -= 0x1800
		
		SSSonic.YPos += SSSonic.YVelocity
		
		// Touched the ground?
		if SSSonic.YPos < 0
			SSSonic.YPos = 0
			
			if HUD[4].SpeedShoes == 0
				SSSonic.State     = SSSONIC_WALKING
				
				SSSonic.Frame     = ANI_WALKING_START
				SSSonic.FrameLoop = ANI_WALKING_LOOP
				SSSonic.FrameEnd  = ANI_WALKING_END
				
				SSSonic.FrameTimer = 0
			else
				SSSonic.State     = SSSONIC_SPEEDSHOESRUN
				
				SSSonic.Frame     = ANI_RUN_START
				SSSonic.FrameLoop = ANI_RUN_LOOP
				SSSonic.FrameEnd  = ANI_RUN_END
				
				SSSonic.AnimationSpeed = 80
				SSSonic.FrameTimer = 0
			end if
		end if
		break
		
	case SSSONIC_SPEEDBOOSTER
		CallFunction(Sonic_ProcessPlayer)
		
		if SSSonic.Speed < 0x50000
			SSSonic.Speed += 0x0800
		end if
		
		if inputdown[1].Down == true
			SSSonic.Speed -= 0x0C00
			
			if SSSonic.Speed < 0x1E000
				SSSonic.Speed = 0x1E000
			end if
		end if
		
		CallFunction(Sonic_HandleMovement)
		CallFunction(Sonic_ProcessAnimation)
		
		// Update the booster timer
		if SSSonic.Timer > 0
			SSSonic.Timer--
			SSSonic.XPos += SSSonic.ScreenXPos
			SSSonic.ZPos += SSSonic.ScreenYPos
		else
			// Booster's over, restore the player to normal
			
			if HUD[4].SpeedShoes == 0
				SSSonic.State     = SSSONIC_WALKING
				
				SSSonic.Frame     = ANI_WALKING_START
				SSSonic.FrameLoop = ANI_WALKING_LOOP
				SSSonic.FrameEnd  = ANI_WALKING_END
				
				SSSonic.FrameTimer = 0
			else
				SSSonic.State     = SSSONIC_SPEEDSHOESRUN
				
				SSSonic.Frame     = ANI_RUN_START
				SSSonic.FrameLoop = ANI_RUN_LOOP
				SSSonic.FrameEnd  = ANI_RUN_END
				
				SSSonic.AnimationSpeed = 80
				SSSonic.FrameTimer = 0
			end if
			
		end if
		
	//	CallFunction(Sonic_HandleTileInteractions)
		
		// See if the player wants to jump out of the boost
		if object.JumpPress == true
			SSSonic.State     = SSSONIC_JUMPING
			SSSonic.Timer     = 0
			
			SSSonic.Frame     = ANI_JUMPING_START
			SSSonic.FrameLoop = ANI_JUMPING_LOOP
			SSSonic.FrameEnd  = ANI_JUMPING_END
			
			SSSonic.AnimationSpeed = 80
			SSSonic.YVelocity = 0x46000
			
			PlaySfx(SFX_G_JUMP, false)
		end if
		break
		
	case SSSONIC_FAN
		CallFunction(Sonic_ProcessPlayer)
		
		if SSSonic.Speed < 0x50000
			SSSonic.Speed += 0x0800
		end if
		
		CallFunction(Sonic_HandleMovement)
		CallFunction(Sonic_ProcessAnimation)
		
		// Gravity of 0.03125 pixels per frame, the fan provides some air resistance to lessen the normal gravity from 0.125 pixels per frame
		SSSonic.YVelocity -= 0x0800
		
		SSSonic.YPos += SSSonic.YVelocity
		
		// Touched the ground?
		if SSSonic.YPos < 0
			SSSonic.YPos = 0
			
		
				if HUD[4].SpeedShoes == 0
					SSSonic.State     = SSSONIC_WALKING
					
					SSSonic.Frame     = ANI_WALKING_START
					SSSonic.FrameLoop = ANI_WALKING_LOOP
					SSSonic.FrameEnd  = ANI_WALKING_END
					
					SSSonic.FrameTimer = 0
				else
					SSSonic.State     = SSSONIC_SPEEDSHOESRUN
					
					SSSonic.Frame     = ANI_RUN_START
					SSSonic.FrameLoop = ANI_RUN_LOOP
					SSSonic.FrameEnd  = ANI_RUN_END
					
					SSSonic.AnimationSpeed = 80
					SSSonic.FrameTimer = 0
				end if
			
		end if
		break
		
	case SSSONIC_TRIPPED
		CallFunction(Sonic_HandlePause)
		
		// Lock movement
		object.Left = false
		object.Right = false
		
		CallFunction(Sonic_HandleMovement)
		CallFunction(Sonic_ProcessAnimation)
		
		// Get the player's truncated XPos and ZPos
		
		temp0 = SSSonic.XPos
		temp0 >>= 16
		
		temp1 = SSSonic.ZPos
		temp1 >>= 16
		
		Get16x16TileInfo(CheckResult, temp0, temp1, TILEINFO_ANGLEA)
		
		// If the player's hit a bumper tile, then get up and start walking again
		if CheckResult == 3
			SSSonic.State     = SSSONIC_WALKING
			
			SSSonic.Frame     = ANI_WALKING_START
			SSSonic.FrameLoop = ANI_WALKING_LOOP
			SSSonic.FrameEnd  = ANI_WALKING_END
			
			SSSonic.FrameTimer = 0
		end if
		
		if SSSonic.Timer > 0
			SSSonic.Timer--
		else
			if HUD[4].SpeedShoes == 0
				SSSonic.State     = SSSONIC_WALKING
				
				SSSonic.Frame     = ANI_WALKING_START
				SSSonic.FrameLoop = ANI_WALKING_LOOP
				SSSonic.FrameEnd  = ANI_WALKING_END
				
				SSSonic.FrameTimer = 0
			else
				SSSonic.State     = SSSONIC_SPEEDSHOESRUN
				
				SSSonic.Frame     = ANI_RUN_START
				SSSonic.FrameLoop = ANI_RUN_LOOP
				SSSonic.FrameEnd  = ANI_RUN_END
				
				SSSonic.AnimationSpeed = 80
				SSSonic.FrameTimer = 0
			end if
		end if
		break
		
	case SSSONIC_SPEEDSHOESRUN
		CallFunction(Sonic_ProcessPlayer)
		
		CallFunction(Sonic_ProcessPlayer)
		if inputdown.up == 1	//if holding up, move
			if SSSonic.Speed < 0x50000
				SSSonic.Speed += 0x1000
			else
				SSSonic.Speed = 0x50000
			end if
		else	//else slow down
			if SSSonic.Speed >= 0
				SSSonic.Speed -= 0x1000
			else	//if ur speed is 0 ur idle again
				SSSonic.Speed = 0
				SSSonic.state = SSONIC_IDLE
			end if	
		end if	
		
		if inputdown[1].Down == true
			SSSonic.Speed -= 0x0C00
			
			if SSSonic.Speed < 0x1E000
				SSSonic.Speed = 0x1E000
			end if
		end if
		
		if inputdown[1].Down == true
			SSSonic.Speed -= 0x0C00
			
			if SSSonic.Speed < 0x1E000
				SSSonic.Speed = 0x1E000
			end if
		end if
		
		CallFunction(Sonic_HandleMovement)
		CallFunction(Sonic_ProcessAnimation)
		
		if SSSonic.Timer > 0
			SSSonic.Timer--
			SSSonic.XPos += SSSonic.ScreenXPos
			SSSonic.ZPos += SSSonic.ScreenYPos
		end if
		
	//	CallFunction(Sonic_HandleTileInteractions)
		
		if object.JumpPress == true
			SSSonic.State     = SSSONIC_JUMPING
			SSSonic.Timer     = 0
			
			SSSonic.Frame     = ANI_JUMPING_START
			SSSonic.FrameLoop = ANI_JUMPING_LOOP
			SSSonic.FrameEnd  = ANI_JUMPING_END
			
			SSSonic.FrameTimer = 0
			SSSonic.AnimationSpeed = 80
			SSSonic.YVelocity = 0x46000
			
			PlaySfx(SFX_G_JUMP, false)
		end if
		
		if HUD[4].SpeedShoes == 0
			SSSonic.State     = SSSONIC_WALKING
			
			SSSonic.Frame     = ANI_WALKING_START
			SSSonic.FrameLoop = ANI_WALKING_LOOP
			SSSonic.FrameEnd  = ANI_WALKING_END
			
			SSSonic.FrameTimer = 0
		end if
		break
		
	case SSSONIC_FINISHSTAND
		SSSonic.Frame = ANI_STANDING_START
		SSSonic.Timer = 0
		SSSonic.Speed = 0
		break
		
	case SSSONIC_CAMERAPAN
		// This state is given to Sonic from the Time Stone object, not from himself
		
		if SSSonic.Timer < 128
			SSSonic.Timer++
			SSSonic.Angle -= 2
			if SSSonic.Angle < 0
				SSSonic.Angle += 512
			end if
		else
			if Object[3].Type == TypeName[Blank Object]
				// Spawn the Time Stone and place it 24 pixels above the screen
				ResetObjectEntity(3, TypeName[Time Stone], 0, 0, -0x180000)
				Object[3].iXPos = Screen.xcenter
				Object[3].Priority = PRIORITY_ACTIVE
			end if
		end if
		
		// Make Sonic's rotation based on how far into the pan we are
		// -> 81 is the starting Sprite Frame ID of the rotation frames
		SSSonic.Frame = SSSonic.Timer
		SSSonic.Frame >>= 4
		SSSonic.Frame += 81
		break
		
	case SSSONIC_STONEGRABBED
		if SSSonic.Timer == 308
			// Spawn the Stage Results, as the "TIME STONES" variant
			
			Object[30].Type = TypeName[Stage Finish]
			Object[30].ResultsType = STAGEFINISH_T_STONEOBTAINED

		else
			SSSonic.Timer++
		end if
		break
		
	case SSSONIC_SPRING
		CallFunction(Sonic_ProcessPlayer)
		
		if SSSonic.Speed < 0x50000
			SSSonic.Speed += 0x0800
		end if
		
		if inputdown[1].Down == true
			SSSonic.Speed -= 0x0C00
			
			if SSSonic.Speed < 0x1E000
				SSSonic.Speed = 0x1E000
			end if
		end if
		
		CallFunction(Sonic_HandleMovement)
		CallFunction(Sonic_ProcessAnimation)
		
		// Update gravity with an eight of a pixel per frame as a gravity value
		SSSonic.YVelocity -= 0x2000
		SSSonic.YPos += SSSonic.YVelocity
		
		if SSSonic.YPos < 0
			SSSonic.YPos = 0
		
				if HUD[4].SpeedShoes == 0
					SSSonic.State     = SSSONIC_WALKING
					
					SSSonic.Frame     = ANI_WALKING_START
					SSSonic.FrameLoop = ANI_WALKING_LOOP
					SSSonic.FrameEnd  = ANI_WALKING_END
					
					SSSonic.FrameTimer = 0
				else
					SSSonic.State     = SSSONIC_SPEEDSHOESRUN
					
					SSSonic.Frame     = ANI_RUN_START
					SSSonic.FrameLoop = ANI_RUN_LOOP
					SSSonic.FrameEnd  = ANI_RUN_END
					
					SSSonic.AnimationSpeed = 80
					SSSonic.FrameTimer = 0
				end if
		
		end if
		break
	case SSONIC_IDLE
		if SSonic.invulnerable > 0

			SSSonic.YVelocity -= 0x1800
			
			SSSonic.YPos += SSSonic.YVelocity
			
			// Touched the ground?
			if SSSonic.YPos < 0
				SSSonic.YPos = 0
		
				SSSonic.State     = SSSONIC_WALKING
				
				SSSonic.Frame     = ANI_WALKING_START
				SSSonic.FrameLoop = ANI_WALKING_LOOP
				SSSonic.FrameEnd  = ANI_WALKING_END
				
				SSSonic.FrameTimer = 0
			end if

		end if


		CallFunction(Sonic_ProcessPlayer)
		//back frame, and dont animate anytyhing
		SSSonic.Frame = ANI_STANDING_START
		SSSonic.Timer = 0
		SSSonic.Speed = 0

		CallFunction(Sonic_HandleMovement)


		if inputDown.up == 1
			// Fully turned around now and ready to go!
			SSSonic.Timer = 0

			// Start advancing ahead
			SSSonic.State = SSSONIC_WALKING

			SSSonic.Frame = ANI_WALKING_START
			SSSonic.FrameLoop = ANI_WALKING_LOOP
			SSSonic.FrameEnd = ANI_WALKING_END

			SSSonic.Speed = 0
		end if
		

		// Update Sonic's gimmick interaction timer
		if SSSonic.Timer > 0
			SSSonic.Timer--
			SSSonic.XPos += SSSonic.ScreenXPos
			SSSonic.ZPos += SSSonic.ScreenYPos
		end if
		
	//	CallFunction(Sonic_HandleTileInteractions)
		
		// Check for jumping
		if object.JumpPress == true
			SSSonic.State     = SSSONIC_JUMPING
			SSSonic.Timer     = 0
			SSSonic.Frame     = ANI_JUMPING_START
			SSSonic.FrameLoop = ANI_JUMPING_LOOP
			SSSonic.FrameEnd  = ANI_JUMPING_END
			SSSonic.FrameTimer = 0
			SSSonic.AnimationSpeed = 80
			SSSonic.YVelocity = 0x46000
			PlaySfx(SFX_G_JUMP, false)
		end if

	break	
	case SSONIC_DEAD
		
		object.value8++
		if object.value8 == 1
			PlaySfx(SfxName[NULL], 0)
		end if				

		SSSonic.YPos = 0x500000

		if object.value8 == 620
			CallNativeFunction(ExitGame)	
		end if


		SSSonic.ControlMode = 0
		SSSonic.Speed = 0
	break
	case SSSONIC_HURT

		PlayerHealth -= 1
		PlaySfx(SfxName[Hurt], 0)
		SSonic.invulnerable = 80
		SSSonic.State     = SSONIC_IDLE

		// Gravity of 0.125 per frame
		SSSonic.YVelocity -= 0x1800
		
		SSSonic.YPos += SSSonic.YVelocity
		
		// Touched the ground?
		if SSSonic.YPos < 0
			SSSonic.YPos = 0
			
		
				SSSonic.State     = SSSONIC_WALKING
				
				SSSonic.Frame     = ANI_WALKING_START
				SSSonic.FrameLoop = ANI_WALKING_LOOP
				SSSonic.FrameEnd  = ANI_WALKING_END
				
				SSSonic.FrameTimer = 0
		
		end if



	break
	end switch
	
	// Enforce stage bounds
	// These stage size values are set by the stage's BGEffects object on Startup
	
	if SSSonic.XPos > Stage.curXBoundary2
		SSSonic.XPos = Stage.curXBoundary2
	end if
	
	if SSSonic.XPos < Stage.curXBoundary1
		SSSonic.XPos = Stage.curXBoundary1
	end if
	
	// The Stage Bounds are setup for a 2d plane, which is why ZPos is being paired with the "Y" Bounds here
	if SSSonic.ZPos > Stage.curYBoundary2
		SSSonic.ZPos = Stage.curYBoundary2
	end if
	
	if SSSonic.ZPos < Stage.curYBoundary1
		SSSonic.ZPos = Stage.curYBoundary1
	end if
	
	// So we're kind of not actually moving around a 3d stage - instead, we're moving the entire world around Sonic
	// So do the calculations for that
	
	TileLayer[0].Angle = SSSonic.Angle
	
	// X/Z movement
	Sin(TileLayer[0].XPos, TileLayer[0].Angle)
	Cos(TileLayer[0].ZPos, TileLayer[0].Angle)
	TileLayer[0].XPos *= -0xA00
	TileLayer[0].ZPos *= -0xA00
	TileLayer[0].XPos += SSSonic.XPos
	TileLayer[0].ZPos += SSSonic.ZPos
	
	// Y movement is much easier, no complex calcuations needed here
	// Just take Sonic's Y Position, smooth it out a bit, and offset it by 88 pixels
	TileLayer[0].YPos = SSSonic.YPos
	TileLayer[0].YPos /= 3
	TileLayer[0].YPos += 0x280000
	
end event


event ObjectDraw

	// First draw Sonic's shadow
	
	// Find his the ground position to draw the shadow on
	temp0 = TileLayer[0].YPos
	temp0 >>= 8
	temp0 *= 96
	temp0 /= 0x5800
	temp0 += 128
	
	// And now draw the shadow at that given spot
//	DrawSpriteScreenXY(0, Screen.xcenter, temp0)
	
	// And now draw Sonic himself
	
	// Get the Y position to draw him at
	temp0 = TileLayer[0].YPos
	temp0 -= SSSonic.YPos
	temp0 >>= 8
	temp0 *= 96
	temp0 /= 0x5800
	temp0 += 128
	

	// Just draw Sonic's sprite, nothing special needed here
//	DrawSpriteScreenXY(1, Screen.xcenter, temp0)

// Just draw Sonic's sprite, nothing special needed here
	temp0 /= 8
	if object.visible == 1
		DrawSpriteScreenXY(2, Screen.xcenter, temp0)	

		DrawSpriteScreenXY(3, Screen.xcenter, temp0)		
	end if
end event


event ObjectStartup
	// Load the correct sprite sheet based on the current player
	LoadSpriteSheet("3D_Test/Sonic.gif")
	
	// Place a Sonic object into reserved object slot 2 and initialise its values
	SSSonic[2].Type = TypeName[Sonic]
	
	// Make Sonic always active
	SSSonic[2].Priority = PRIORITY_ACTIVE
	
	// Give him a standard draw order depth, since he's just about in the middle of the screen
	SSSonic[2].ScreenDepth = 0x5800
	
	Object[2].DrawOrder = 5
	
	// Cycle through the scene to find all Sonic objects
	ArrayPos0 = 32
	while ArrayPos0 < 1056
		if Object[ArrayPos0].Type == TypeName[Sonic]
			
			// Transfer this placed Sonic object's values to the main Sonic object
			
			SSSonic.XPos = Object[ArrayPos0].XPos
			
			// Due to the difference between editor and game, turn YPos into ZPos here
			SSSonic[2].ZPos = Object[ArrayPos0].YPos
			
			// And then reset YPos, so that he's starting on the floor
			SSSonic.YPos = 0
			
			// PropertyValue is Sonic's starting direction
			// Sonic's PropertyValue is normally always 0xC0, which is facing left
			SSSonic.Angle = Object[ArrayPos0].PropertyValue
			SSSonic.Angle <<= 1
			
			// Remove this placed Sonic object from the scene set of objects,
			// as it's been moved to a reserved object slot now
			ResetObjectEntity(ArrayPos0, TypeName[Blank Object], 0, 0, 0)
			
		end if
		
		ArrayPos0++
	loop
	
	// Player Frames
	// Refer to the ANI_* constants too, those are a good outline of what these SpriteFrames are
	
	// 0 - Shadow Frame
	SpriteFrame(-20, -4, 40, 8, 210, 377)
	
	// 1 - Standing Frame
	SpriteFrame(-20, -48, 40, 48, 1, 197)

	// 2 - flash hand
	SpriteFrame(80, 140, 96, 96, 1, 415)	

	// 3 - flash hand
	SpriteFrame(-160, 140, 96, 97, 98, 415)	

	// 23 - SLENDERMAN!!
	SpriteFrame(-30, -32, 63, 112, 339, 1)

	SpriteFrame(-24, -30, 88, 88, 0, 413) //33	

end event


// ========================
// Editor events
// ========================

event RSDKEdit
	if Editor.ReturnVariable == true
		switch Editor.VariableID
		case EDIT_VAR_PROPVAL // Property Value
			CheckResult = Object.PropertyValue
			break
		case 0 // StartDir
			CheckResult = Object.PropertyValue
			break
		end switch
	else
		switch Editor.VariableID
		case EDIT_VAR_PROPVAL // Property Value
			Object.PropertyValue = Editor.VariableValue
			break
		case 0 // StartDir
			Object.PropertyValue = Editor.VariableValue
			break
		end switch
	end if
end event


event RSDKDraw
	DrawSprite(0)
end event


event RSDKLoad
	LoadSpriteSheet("3D_Test/Sonic.gif")
	SpriteFrame(-20, -48, 40, 48, 1, 246)

	AddEditorVariable("StartDir")
	SetActiveVariable("StartDir")
	AddEnumVariable("Up", 0)
	AddEnumVariable("Right", 64)
	AddEnumVariable("Down", 128)
	AddEnumVariable("Left", 192)
end event
